package org.sidora.core;


import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

//import matrix.Diagrama;
//import matrix.PersistedData;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;
import org.sidora.core.context.Context;
import org.sidora.core.util.AbstractFactory;
import org.sidora.core.util.AbstractInventory;
import org.sidora.core.util.OCProvider;
import org.sidora.core.util.ParameterCollector;



/**
 * Feature
 * @author Enric Tartera, Anna Arnalot, Juan Manuel Gimeno, Roger Masgoret
 * @version 1.0
 */
public class Feature implements Comparable, Describable{
    
    private KeyObject idFet;
    
    //TODO mirar
    private TreeSet<Action> archactions = new TreeSet<Action>();
    //private TreeSet<Assignment> assignments;
    
    private TreeSet <Sector> sectors = new TreeSet<Sector>();
    //private TreeSet <Context> composition= new TreeSet<Context>();
    private TreeSet <Context> relatedContexts= new TreeSet<Context>();
    private TreeSet <Feature> relatedFeatures= new TreeSet<Feature>();
    //private String name;
    public Category featureType;
    private String commentary;
    
    //private PersistedData diagrama;
    
    
    private Feature(){}
    
    
    
    public TreeSet<Context> getComposition() {
        List list = Context.Inventory.getList(this);
        return new TreeSet<Context>(list);
    }
    
    public KeyObject getIdFet() {
        return idFet;
    }
    
    public void setIdFet(KeyObject idFet) {
        this.idFet = idFet;
    }
    
    public String getName() {
        if (featureType!=null){
        String string = featureType.getLabel()+idFet.getNumberString();
        return string; //MR-172
        }
        else return "??-"+idFet.getNumberString();
    }
    
    
    public TreeSet<Context> getRelatedContexts() {
        return relatedContexts;
    }
    
    public void setRelatedContexts(TreeSet<Context> relatedContexts) {
        this.relatedContexts = relatedContexts;
    }
    
    
    public TreeSet<Sector> getSectors() {
        return sectors;
    }
    
    public void setSectors(TreeSet<Sector> sectors) {
        this.sectors = sectors;
    }
    
    
    
    
//    public PersistedData getDiagrama() {
//        return diagrama;
//    }
//
//
//
//    public void setDiagrama(PersistedData diagrama) {
//        this.diagrama = diagrama;
//    }
    
    
    
    public boolean equals(Object obj) {
        if (obj == this)	return true;
        if (!(obj instanceof Feature)) return false;
        Feature feature = null;
        try {
            feature = (Feature) obj;
        } catch (Exception e) {
            return false;
        }
        if (this.idFet != feature.idFet) return false;
        return true;
    }
    
    @Override
    public String toString() {
        String text = "";
        if (getFeatureType() == null) {
            text= "Fet: ??-"+idFet.getNumber();
        }else{
            
            text= "Fet: "+getName();
        }//
        return text;
    }
    public String toSmallString() {
        String text = "";
        if (getFeatureType() == null) {
            text= "??-"+idFet.getNumber();
        }else{
            
            text= getName();
        }//
        return text;
    }
    
    
    
//    private static class Factory extends AbstractFactory{
//
//        protected Object create(ParameterCollector param) {
//            // La pol�tica de creaci� de sectors determina que un usuari
//            // amb rol "admin" o "user" pot crear noves inst�ncies.
//            // Per defecte es permet tamb? el password de root declarat com a variable est�tica de User
//
//            return new Feature();
//
//        }
//    }
    public static class Inventory extends AbstractInventory{
        
        public boolean exist(final KeyObject id) throws Exception{
            
            ObjectContainer db = OCProvider.getInstance();
            ObjectSet<Feature> fets = db.query(new Predicate<Feature>() {
                public boolean match(Feature candidate) {
                    return candidate.idFet.equals(id);
                }
            });
            
            if (fets.hasNext()){
                return true;
            } else {
                return false;
            }
        }
        
        public Feature getNewObject(ParameterCollector param) throws Exception{
            KeyObject newId= getNewKey(param);
            
            //Delega en la factoria la creaci�
            //param.put("factoryid", "Feature");

            Feature fet = new Feature();//(Feature) Feature.Factory.createObject(param);
            fet.setFeatureType((Category)param.get("type"));
            fet.idFet =newId;
            //Add a Default action if it's not null
            if (param.get("action") != null)
                fet.getArchactions().add((Action) param.get("action"));
            
            return fet;
            
            
            
        }
        
        public KeyObject getNewKey(ParameterCollector param) {
            //Cal passar els parametres site y zona tot i que nom?s el site �s fonamental
            
            Zone zone = (Zone) param.get("zone");
            final Site site = zone.getSite();//(Site) param.get("site");
            //se li dona el valor inicial per defecte
            KeyObject key = new KeyObject();
            key.setNumber(1);
            key.setSite(zone.getSite());
            key.setZone(zone);
            //es busca a la base d'objectes totes les inst�ncies de Fets del jaciment
            ObjectContainer db = OCProvider.getInstance();
            
            List <Feature>fets = db.query(new Predicate <Feature> (){
                @Override
                public boolean match(Feature candidate) {
                    return candidate.idFet.getSite().equals(site);
                }
            });
            //En cas que hi hagi d'altres fets al jaciment busca el nombre m�s alt i en suma un
            if (fets.size()!= 0){
                TreeSet <Feature> tree = new TreeSet<Feature>(fets);
                Feature fet = tree.last();
                Integer integer = fet.idFet.getNumber()+1;
                key.setNumber(integer);
                return key;
            }
            //En cas contrari pasa el valor per defecte
            else return key;
            
        }
        
        
        public Object getObject(ParameterCollector param) {
            //Carrega el Fet amb el corresponent keyobject
            final KeyObject key = (KeyObject) param.get("id");
            ObjectContainer db = OCProvider.getInstance();
            
            ObjectSet <Feature> fets = db.query(new Predicate <Feature>() {
                public boolean match(Feature afet) {
                    return (afet.idFet.equals(key));
                }
            });
            
            if (fets.hasNext()){
                return fets.next();
            } else throw new RuntimeException("Fet inexistent");
        }
        
        public static List getList() {
            
            ObjectContainer db = OCProvider.getInstance();
            List<Feature> list = db.query(Feature.class);
            
            return list;
            
        }
        
        public static List<Feature> getList(final Site site) {
            ObjectContainer db = OCProvider.getInstance();
            List<Feature> list = db.query(new Predicate<Feature>(){
                
                @Override
                public boolean match(Feature feature) {
                    
                    return feature.idFet.getSite()==site;
                }});
                
                return list;
        }
        
        
        public static List<Feature> getList(final Zone zone) {
            ObjectContainer db = OCProvider.getInstance();
            List<Feature> list = db.query(new Predicate<Feature>(){
                
                @Override
                public boolean match(Feature feature) {
                    
                    return feature.idFet.getZone()==zone;
                }});
                
                return list;
        }
        
        
        public static List<Feature> getList(final Sector sector) {
            ObjectContainer db = OCProvider.getInstance();
            List<Feature> list = db.query(new Predicate<Feature>(){
                
                @Override
                public boolean match(Feature feature) {
                    //Es pregunta directament a feature ja que conté un col·lecció de sectors
                    return feature.sectors.contains(sector);
                }});
                
                return list;
        }
        
        
    }
    public int compareTo(Object obj) {
        Feature afet = (Feature) obj;
        return this.idFet.compareTo(afet.idFet);
    }
    
    public Site getSite() {
        return this.idFet.getSite();
    }
    
    public Category getFeatureType() {
        return featureType;
    }
    
    public void setFeatureType(Category featureType) {
        this.featureType = featureType;
    }
    
    public String getCommentary() {
        return commentary;
    }
    
    public void setCommentary(String commentary) {
        this.commentary = commentary;
    }
    
    public TreeSet<Action> getArchactions() {
        return archactions;
    }
    
    public void setArchactions(TreeSet<Action> archactions) {
        this.archactions = archactions;
    }
    
    public TreeSet<Feature> getRelatedFeatures() {
        return relatedFeatures;
    }
    
    public void setRelatedFeatures(TreeSet<Feature> relatedFeatures) {
        this.relatedFeatures = relatedFeatures;
    }
}



